#include "OmegaModel.h"

using namespace std;

OmegaModel::OmegaModel(void)
{
	meshes = 0;
	numberOfMeshes = 0;
	memblock = 0;
	animated = false;

}

OmegaModel::OmegaModel(char* fname, GLuint(*f)(char*)){

	meshes = 0;
	numberOfMeshes = 0;
	memblock = 0;
	animated = false;
	this->loadModel(fname, f);

}

void OmegaModel::loadModel(char* fname, GLuint(*f)(char*))
{
	int size;
	char * memblock;

	// ios::ate opens file at the end
	ifstream file (fname, ios::in|ios::binary|ios::ate);
	if (file.is_open())
	{
		size = (int) file.tellg(); // get location of file pointer i.e. file size
		memblock = new char [size+1]; // create buffer with space for null char
		file.seekg (0, ios::beg);
		file.read (memblock, size);
		file.close();
		memblock[size] = 0;
		cout << "File " << fname << " loaded. Parsing..." << endl << endl;
	}
	else
	{
		cout << "Unable to open file " << fname << endl;
		// should ideally set a flag or use exception handling
		// so that calling function can decide what to do now
	}

	stringstream strstream(memblock);
	string fptr;
	strstream >> fptr;
	if(fptr.compare(0,14,"alphameshlistV")!=0)
	{
		cout << "'" << fname << "', is not in the correct format."<< endl;		
	}
	else
	{
		fptr = fptr.substr(13,16);
		//cout << "Model Version '" << fptr.c_str() << "' This *should* be fine." << endl;

		strstream >> fptr;
		if(fptr.compare(0,1,"t")!=0 || fptr.compare(0,1,"T")!=0)
		{
			animated = false;
		}
		else
		{
			animated = true;
		}
		strstream >> numberOfMeshes;

		this->meshes = new OmegaMesh[numberOfMeshes];
		this->textures = new GLuint[numberOfMeshes];
		/*this->normalMaps = new GLuint[numberOfMeshes];
		this->specMaps = new GLuint[numberOfMeshes];
		this->nightmap = new GLuint[numberOfMeshes];*/

		for(int i=0;i<numberOfMeshes;i++)
		{
			strstream >> fptr;
			meshes[i].loadMesh(fptr.c_str());
			strstream >> fptr;
			if(fptr.compare(0,7,"default")==0)
			{
				textures[i] = f("def.png");
				//Loaders::loadImg("def.png",&textures[i]);
			}
			else
			{
				textures[i] = f(const_cast<char*>(fptr.c_str()));
				//Loaders::loadImg(fptr.c_str(),&textures[i]);
			}
		}
	}	
}



void OmegaModel::display(AlphaMatrix* mvm,AlphaMatrix* proj,float* lightPos, GLuint s)
{
	/*GLuint s = Utilities::useShader("default.shader");
	glUseProgram(s);*/
	int ui = glGetUniformLocation(s,"MVM");
	glUniformMatrix4fv(ui,1,GL_FALSE,mvm->returnPtr());

	ui = glGetUniformLocation(s,"PROJ");
	glUniformMatrix4fv(ui,1,GL_FALSE,proj->returnPtr());

	ui = glGetUniformLocation(s,"tu0");
	glUniform1i(ui,0);

	ui = glGetUniformLocation(s,"tu1");
	glUniform1i(ui,1);

	ui = glGetUniformLocation(s,"tu2");
	glUniform1i(ui,2);

	ui = glGetUniformLocation(s,"tu3");
	glUniform1i(ui,3);

	ui = glGetUniformLocation(s,"lightPosition");
	glUniform4fv(ui,1,lightPos);
	for(int i=0;i<numberOfMeshes;i++)
	{
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D,textures[i]);
		meshes[i].display();
	}
}

GLuint OmegaModel::getTexture(int mesh)
{

	if(mesh > numberOfMeshes || mesh < 0)
	{
		cerr << "Trying to access element outwith array" << endl;
		return 0;
	}else
	{
		return textures[mesh];
	}

}

//void OmegaModel::setShader(Shader *iS, int mesh)
//{
//
//	if(mesh > numberOfMeshes || mesh < 0){
//		cerr << "Trying to access element outwith array" << endl;
//	}else{
//		meshes[mesh].setNewShader(iS);
//	}
//
//}

void OmegaModel::setNormalMap(GLuint iNM, int mesh)
{

	if(mesh > numberOfMeshes || mesh < 0){
		cerr << "Trying to access element outwith array" << endl;
	}
	else
	{
		this->normalMaps[mesh] = iNM;
	}

}

void OmegaModel::setTexture(GLuint iT,int mesh)
{
	if(mesh > numberOfMeshes || mesh < 0)
	{
		cerr << "Trying to access element outwith array" << endl;
	}
	else
	{
		this->textures[mesh] = iT;
	}
}

void OmegaModel::setSpecMap(GLuint iSM,int mesh)
{
	if(mesh > numberOfMeshes || mesh < 0)
	{
		cerr << "Trying to access element outwith array" << endl;
	}
	else
	{
		this->specMaps[mesh] = iSM;
	}
}
void OmegaModel::setNightMap(GLuint iNM,int mesh)
{
	if(mesh > numberOfMeshes || mesh < 0)
	{
		cerr << "Trying to access element outwith array" << endl;
	}
	else
	{
		this->nightmap[mesh] = iNM;
	}
}



OmegaModel::~OmegaModel(void)
{
}
